package org.dftproject.genesis.core.persistence.bdb;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dftproject.genesis.core.persistence.IPersistable;
import org.dftproject.genesis.core.persistence.IPersistenceFactory;
import org.dftproject.genesis.core.persistence.Memento;
import org.dftproject.genesis.core.persistence.PersistenceUtils;

import com.sleepycat.bind.tuple.TupleBinding;
import com.sleepycat.bind.tuple.TupleInput;
import com.sleepycat.bind.tuple.TupleOutput;

public class PersistenceBinding extends TupleBinding {

	private static final Log log = LogFactory.getLog(PersistenceBinding.class);

	@Override
	public void objectToEntry(Object object, TupleOutput output) {	
		if (!(object instanceof IPersistable))
			throw new IllegalArgumentException("object must be persistable");
		
		try {
			Memento memento = new Memento();
			((IPersistable) object).saveState(memento);
			
			output.writeString(((IPersistable) object).getFactoryId());
			
			ByteArrayOutputStream os = new ByteArrayOutputStream();
			memento.store(os);
			
			byte[] data = os.toByteArray();
			output.writeInt(data.length);
			output.write(data);
		} catch (IOException e) {
			log.error("Failed to convert persistable to a tuple entry", e);
		}
	}

	@Override
	public Object entryToObject(TupleInput input) {
		try {
			String factoryId = input.readString();
			if (factoryId == null)
				return null;
			
			IPersistenceFactory factory = PersistenceUtils.getFactory(factoryId);
			if (factory == null)
				return null;
			
			byte[] data = new byte[input.readInt()];
			input.read(data);
			
			return factory.createObject( new Memento(new ByteArrayInputStream(data)));
		} catch (IOException e) {
			log.error("Failed to convert tuple entry to a persistable", e);
		}
		
		return null;
	}

}
